#!usr/bin/python
# -*- coding: utf8 -*-
encoding='utf8'

import codecs

## Start concatenation ##

def readFile(filename):
    charmaps = ('cp1251', 'cp866', 'utf8')
    for cmap in charmaps:
        try:
            content = codecs.open(filename, 'r', cmap).read()
        except UnicodeDecodeError:
            continue
        except TypeError, e:
            print u'readFile() TypeError:'
            print u'Filename: "%s"' % (filename)
            print u'Charmap:  "%s"' % (cmap)
            raise e
        else:
            return content
    raise UnicodeDecodeError

class Iter_plus(object):
    def __init__(self, tokens = None):
        if not tokens:
            self.tokens = []
        else:
            self.tokens = tokens
        self.current_token = 0
        self.position_stack = []
        self.slices = []
        tokens = None

    def pos(self):
        return self.current_token

    def pushPosition(self):
        self.position_stack.append(self.pos())

    def popPosition(self):
        self.current_token = self.position_stack.pop()

    def current(self):
        try:
            return self.tokens[self.current_token]
        except IndexError:
            if self.current_token >= len(self.tokens):
                raise IndexError, "EOF"
            elif self.current_token < 0:
                raise IndexError, "Negative line number"

    def prev(self):
        if self.current_token-1 >= 0:
            return self.tokens[self.current_token-1]
        else:
            return None


    def next(self):
        if self.current_token+1 < len(self.tokens):
            return self.tokens[self.current_token+1]
        else:
            return None

    def first(self):
        return self.tokens[0]

    def last(self):
        return self.tokens[-1]

    def read(self):
        t = self.current()
        self.move(1)
        return t

    def byToken(self, do_not_reset = False):
        if not do_not_reset:
            self.current_token = 0
        while self.current_token < len(self.tokens):
            # Not using read here to move cursor on next iteration
            # Another words, to hold cuurent token for edit
            yield self.current()
            self.move(1)

    def remove(self, and_step_back = False):
        del self.tokens[self.current_token]
        if and_step_back:
            self.move(-1)

    def prepend(self, token):
        self.tokens.insert(self.current_token, token)
        self.move(1)

    def append(self, token):
        self.tokens.insert(self.current_token+1, token)

    def push_front(self, token):
        self.tokens = [token] + self.tokens
        self.move(1)

    def push_back(self, token):
        self.tokens.append(token)

    def replace(self, token):
        self.tokens[self.current_token] = token

    def move(self, tokens_count):
        self.current_token+= tokens_count

    def get(self):
        return self.tokens

    def startSlice(self):
        self.slices.append(pos)
        return len(self.slices) - 1

    def getSlice(self, slice_id):
        slice = Iter_plus()
        start = self.slices[slice_id]
        del self.slices[slice_id]
        for p in range(start, self.current_token+1):
            slice.append(self.tokens[p])
            slice.move(1)
        return slice

    def __len__(self):
        return len(self.tokens)

    def splitBy(self, text):
        result = []
        current = []
        self.pushPosition()
        for t in self.byToken():
            if t.node_type == 'leaf' and t.text() == text:
                result.append( current )
                current = []
            else:
                current.append(t)
        if len(current):
            result.append( current )
        self.popPosition()
        return result

class Origin(object):
    def __init__(self, filename, line_id, text):
        self.filename = filename
        self.line_id  = line_id
        self.text     = text

    def debug(self):
        output = u''
        output+= u'%s[%d]: %s' % (self.filename, self.line_id, self.text)
        return output

class Source_line(object):
    def __init__(self, filename, line_id, text):
        self.origin  = Origin(filename, line_id, text)
        self.line_id = line_id
        self.text    = text

class Source(object):
    def __init__(self, text):
        assert(type(text) == unicode)
        self.src = text
        self.text = text
        self.splitted = self.__splitLines(text)
        self.lines = []
        for id, line in enumerate(self.splitted):
            self.lines.append(Source_line(None, id, line))
        self.read_line = 0
        self.edit_line = 0
        self.cur_pos = 0
        self.filename = 'Undefined filename'

    def setFilename(self, filename):
        self.filename = filename
        for line in self.lines:
            line.origin.filename = filename
        #print 'setFilename:', filename

    def current(self):
        try:
            return self.lines[self.read_line].text
        except IndexError:
            if self.read_line >= len(self.lines):
                raise IndexError, "EOF"
            elif self.read_line < 0:
                raise IndexError, "Negative line number"

    def lineId(self):
        return self.read_line

    def origin(self):
        orig = self.lines[self.read_line].origin
        output = u'%s[%d]: %s' % (orig.filename, orig.line_id, orig.text)
        return output

    def getFilename(self):
        return self.lines[self.read_line].origin.filename

    def getOrigin(self):
        return self.lines[self.read_line].origin

    def byLine(self, do_not_reset = False):
        if not do_not_reset:
            self.edit_line = 0
            self.read_line = 0
        while self.read_line < len(self.lines):
            self.edit_line = self.read_line
            yield self.current()
            self.moveLine(1)

    def removeLine(self, and_step_back = False):
        del self.lines[self.edit_line]
        if and_step_back:
            self.moveLine(-1)

    def insertLine(self, text):
        line = Source_line(self.filename, self.edit_line, self.__stripLine(text))
        self.lines.insert(self.edit_line, line)
        self.moveLine(1)

    def replaceLine(self, text):
        origin = self.lines[self.edit_line].origin
        line = Source_line(self.filename, self.edit_line, self.__stripLine(text))
        line.origin = origin
        self.lines[self.edit_line] = line

    def moveLine(self, lines_count):
        self.edit_line+= lines_count
        self.read_line+= lines_count

    def include(self, source):
        return_pos = [self.read_line, self.edit_line]
        for line in source.lines:
            self.lines.insert(self.edit_line, line)
            self.moveLine(1)
        self.read_line, self.edit_line = return_pos

    def get(self):
        #return u'\r\n'.join([u'%s[%d]: %s' % (a.origin.filename, a.origin.line_id, a.text) for a in self.lines])
        return u'\r\n'.join([a.text for a in self.lines])

    def get_debug(self):
        output = u''
        for i, l_ in enumerate(self.lines):
            l = l_.text
            prefix = list(u'    ')
            if self.read_line == i: prefix[2] = u'r'
            if self.edit_line == i: prefix[1] = u'e'
            output+= u''.join(prefix)
            output+= l
            output+= u'\n'
        return output

    def __stripLine(self, line):
        while len(line) and (line[-1] in u'\r\n'):
            line = line[:-1]
        return line

    def __splitLines(self, text):
        cur = u''
        result = []
        for c in text:
            if c == u'\n':
                result.append( self.__stripLine(cur) )
                cur = u''
            else:
                cur+= c
        if(len(cur)):
            result.append( cur )
        return result

## Stop concatenation ##

def main():
    s = Source(codecs.open('Source.py', 'r', 'utf8').read())
    s = Source(u'c = a + b;')
    assert(s.current() == u'c = a + b;')
    s.insertLine(u'd = c * 2;')
    s.moveLine(1);
    s.insertLine(u'e = d + 5;')
    try:
        print s.current()
    except IndexError:
        pass
    else:
        assert(1==0)
    for line in s.byLine():
        print line

if __name__ == '__main__':
    main()
